package com.jingdong.utils;


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 简单表单验证  工具类
 */
public class FormUtils {

    private static Pattern linePattern = Pattern.compile("_(\\w)");
    private static Pattern humpPattern = Pattern.compile("[A-Z]");

    /**
     * 下划线转驼峰
     * @param str
     * @return
     */
    public static String lineToHump(String str) {
        if (null == str || "".equals(str)) {
            return str;
        }
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);

        str = sb.toString();
        str = str.substring(0, 1).toUpperCase() + str.substring(1);

        return str;
    }


    /**
     * 驼峰转下划线,效率比上面高
     * @param str
     * @return
     */
    public static String humpToLine(String str) {
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 驼峰转下划线(简单写法，效率低于{@link #humpToLine(String)})
     * @param str
     * @return
     */
    public static String humpToLine2(String str) {
        return str.replaceAll("[A-Z]", "_$0").toLowerCase();
    }

    /**
     * 首字母转小写
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (FormUtils.isBlank(s)) {
            return s;
        }
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    /**
     * 首字母转大写
     * @param s
     * @return
     */
    public static String toUpperCaseFirstOne(String s) {
        if (FormUtils.isBlank(s)) {
            return s;
        }
        if (Character.isUpperCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuffer()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    /**
     * object转String
     * @param object
     * @return
     */
    public static String getString(Object object) {
        return getString(object, "");
    }

    public static String getString(Object object, String defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        try {
            return object.toString();
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * object转Integer
     * @param object
     * @return
     */
    public static int getInt(Object object) {
        return getInt(object, -1);
    }

    public static int getInt(Object object, Integer defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        try {
            return Integer.parseInt(object.toString());
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * object转Boolean
     * @param object
     * @return
     */
    public static boolean getBoolean(Object object) {
        return getBoolean(object, false);
    }

    public static boolean getBoolean(Object object, Boolean defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        try {
            return Boolean.parseBoolean(object.toString());
        } catch (Exception e) {
            return defaultValue;
        }
    }


    /**
     * 检查是否为null或者""(空串)
     *
     * @param str
     * @return true|为null或者""
     */
    public static boolean isEmpty(String str) {
        if (str == null) {
            return true;
        } else if (str.length() == 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查是否为null或者空白字符串，去除首尾空格后为空的字符串
     *
     * @param str
     * @return true|为null或者trim()后为""
     */
    public static boolean isBlank(String str) {
        if (str == null) {
            return true;
        } else if (str.trim().length() == 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 数组联合，将数组中的元素拼接为字符串，两个元素之间可以自定义分隔符
     *
     * @param stringArray
     *            数组
     * @param separator
     *            分隔符
     * @return 字符串
     */
    public static String join(String[] stringArray, String separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < stringArray.length; i++) {
            if (i > 0) {
                sb.append(separator);
            }
            sb.append(stringArray[i]);
        }
        return sb.toString();
    }

    /**
     * 数组联合，将数组中的元素拼接为字符串，元素之间没有分隔符
     *
     * @param stringArray
     *            数组
     * @return 数组
     */
    public static String join(String[] stringArray) {
        return join(stringArray, "");
    }

    /**
     * 检查字符串与整数的值是否相同
     *
     * @param
     * @param
     * @return true|当两个变量的值相同
     */
    public static boolean isEqual(int arg0, int arg1) {
        return arg0 == arg1;
    }

    /**
     * 检查字符串与整数的值是否相同
     *
     * @param str
     * @param arg
     * @return true|当两个变量的值相同
     */
    public static boolean isEqual(int arg, String str) {
        return isEqual(str, arg);
    }

    /**
     * 检查字符串与整数的值是否相同
     *
     * @param str
     * @param arg
     * @return true|当两个变量的值相同
     */
    public static boolean isEqual(String str, int arg) {
        return (arg + "").equals(str);
    }

    /**
     * 检查两个字符串是否一致,当两个字符串同时为null时返回false
     *
     * @param str1
     * @param str2
     * @return true|当两个字符串相同
     */
    public static boolean isEqual(String str1, String str2) {
        return isEqual(str1, str2, false);
    }

    /**
     * 检查两个字符串是否一致
     *
     * @param str1
     * @param str2
     * @param isNullSame
     *            当两个字符串同时为null时返回ture还是false
     * @return true|两个字符串相同
     */
    public static boolean isEqual(String str1, String str2, boolean isNullSame) {
        if (str1 == null && str2 == null) {
            return isNullSame;
        } else if (str1 == null || str2 == null) {
            return false;
        } else {
            return (str1.equals(str2));
        }
    }

    /**
     * 手机号格式检查
     *
     * @param phone
     *            传入的手机号
     * @return true|为正确的手机号
     */
    public static boolean isPhoneNumber(String phone) {
        // String regExp =
        // "^((13[0-9])|(15[^4])|(18[0,1,2,3,5-9])|(17[0-8])|(147))\\d{8}$";
        String regExp = "^1[3|4|5|7|8][0-9]\\d{4,8}$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(phone);
        return m.matches();
    }

    /**
     * 邮箱格式检查
     *
     * @param email
     *            传入的邮箱
     * @return true|为正确的邮箱格式
     */
    public static boolean isEmail(String email) {
        String regExp = "\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(email);
        return m.matches();
    }

    /**
     * 对qq号进行验证，要求5~15位，不能以0开头，只能是数字
     *
     * @param str
     * @return true|符合验证规则的号码
     */
    public static boolean isQQ(String str) {
        String regExp = "[1-9][0-9]{4,14}";// 第一位1-9之间的数字，第二位0-9之间的数字，数字范围4-14个之间
        // String regExp2 = "[1-9]\\d{4,14}";//此句也可以
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为url
     *
     * @param str
     * @return true|正确的URL
     */
    public static boolean isUrl(String str) {
        // String regExp =
        // "^((https|http|ftp|rtsp|mms)?://)[^\\s]+\\.[^\\s]+/?"; // 简单验证
        String regExp = "^((https|http|ftp|ed2k|thunder|rtsp|mms)://)?[A-Za-z0-9-]+(.[A-Za-z0-9-])+(:\\d)?(/([A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)?)?)*$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否全部为汉字
     *
     * @param str
     *            传入值
     * @return true|当全部为汉字时
     */
    public static boolean isChinese(String str) {
        if (str == null || "".equals(str)) {
            return false;
        } else if (str.length() == str.getBytes().length) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查是否为整数
     *
     * @param str
     * @return true|当为整数时
     */
    public static boolean isInteger(String str) {
        String regExp = "^-?[0-9]+$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为【正】整数
     *
     * @param str
     * @return true|当为正整数时
     */
    public static boolean isIntegerPositive(String str) {
        String regExp = "^0*[1-9]+$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为【非正】整数
     *
     * @param str
     * @return true|当为非正整数时
     */
    public static boolean isIntegerNotPositive(String str) {
        String regExp = "^-0*[1-9]+|0$"; // '-01'判断true
        // String regExp = "^-[1-9]\\d*|0$"; // '-01'判断false
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为【负】整数
     *
     * @param str
     * @return true|当为负整数时
     */
    public static boolean isIntegerNegative(String str) {
        String regExp = "^-0*[1-9]+$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为【非负】整数
     *
     * @param str
     * @return true|当为非负整数时，"01"这种会返回false
     */
    public static boolean isIntegerNotNegative(String str) {
        String regExp = "^0*[1-9]+|0$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为浮点数
     *
     * @param str
     * @return true|当为浮点数时
     */
    public static boolean isFloat(String str) {
        String regExp = "^-?[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为【正】浮点数
     *
     * @param str
     * @return true|当为正浮点数时
     */
    public static boolean isFloatPositive(String str) {
        String regExp = "^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为【负】浮点数
     *
     * @param str
     * @return true|当为负浮点数时
     */
    public static boolean isFloatNegative(String str) {
        String regExp = "^-[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否为数字，包含整数和浮点数，以及正负数
     *
     * @param str
     * @return true|为正数或者浮点数
     */
    public static boolean isNumber(String str) {
        String regExp = "^-?[1-9]\\d*\\.*\\d*|0\\.\\d*[1-9]\\d*$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 帐号是否合法(字母开头，允许5-12字节，允许字母数字下划线)
     *
     * @param str
     * @return true|账号符合要求
     */
    public static boolean isUserName(String str) {
        return isUserName(str, 5, 12);
    }

    /**
     * 帐号是否合法(字母开头，允许字母数字下划线)
     *
     * @param str
     * @param minLength
     *            最小长度
     * @param maxLength
     *            最大长度
     * @return true|账号符合要求
     */
    public static boolean isUserName(String str, int minLength, int maxLength) {
        String regExp = "^[a-zA-Z][a-zA-Z0-9_]{" + minLength + "," + maxLength + "}$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否全部为大写字母
     *
     * @param str
     * @return true|全部为大写字母
     */
    public static boolean isLettersAllUpper(String str) {
        String regExp = "^[A-Z]+$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否全部为小写字母
     *
     * @param str
     * @return true|全部为小写字母
     */
    public static boolean isLettersAllLower(String str) {
        String regExp = "^[a-z]+$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 检查是否同时包含字母大小写
     *
     * @param str
     * @return true|同时有大写和小写字母
     */
    public static boolean isLettersContainUpperAndLower(String str) {
        String regExp = "^(([A-Z]+[a-z]+[A-Za-z]*)|([a-z]+[A-Z]+[A-Za-z]*))$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 是否为合法的密码，同时且只能包含字母数字，长度在6-20位之间
     *
     * @param str
     * @return true|密码中同时包含字母和数字，且长度在6-20位之间
     */
    public static boolean isPasswordOfSimple(String str) {
        return isPasswordOfSimple(str, 6, 20);
    }

    /**
     * 是否为合法的密码，同时且只能包含大小写字母和数字
     *
     * @param str
     * @param minLength
     *            最小长度，必需>=3
     * @param maxLength
     *            最大长度
     * @return true|str中同时包含大小写字母和数字，并且长度合法
     */
    public static boolean isPasswordOfSimple(String str, int minLength, int maxLength) {
        /**
         * 这个叫断言，只匹配一个位置<br/>
         * 比如，你想匹配一个“人”字，但是你只想匹配中国人的人字，不想匹配法国人的人<br/>
         * 就可以用一下表达式 (?=中国)人<br/>
         * (?=.*[a-z])\d+ 这个就表示 匹配以“任意字符连着一个小写字母”开头的数字，只匹配数字。<br/>
         * (?<=exp)这个是放后面的。
         */
        if (minLength < 3) {
            minLength = 3;
        }
        if (maxLength < minLength) {
            return false;
        }
        String regExp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])([a-zA-Z0-9]{" + minLength + "," + maxLength + "})$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 是否为合法的密码，同时且只能包含大小写字母、数字和一个特殊字符，特殊字符：,.!@#$%^&*()_<>?'
     *
     * @param str
     * @return true|str中同时包含大小写字母、数字和一个特殊字符，且长度在6-20位之间
     */
    public static boolean isPasswordOfComplex(String str) {
        return isPasswordOfComplex(str, 6, 20);
    }

    /**
     * 是否为合法的密码，同时且只能包含大小写字母、数字和一个特殊字符，特殊字符：,.!@#$%^&*()_<>?'
     *
     * @param str
     * @param minLength
     *            最小长度，必需>=3
     * @param maxLength
     *            最大长度
     * @return true|str中同时包含大小写字母、数字和一个特殊字符，并且长度合法
     */
    public static boolean isPasswordOfComplex(String str, int minLength, int maxLength) {
        if (minLength < 3) {
            minLength = 3;
        }
        if (maxLength < minLength) {
            return false;
        }
        String regExp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[,.!@#$%^&*()_<>?'])([a-zA-Z0-9!@#$%^&*()_<>?']{"
                + minLength + "," + maxLength + "})$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    /**
     * 身份证号验证
     *
     * @param str
     * @return
     */
    public static boolean isIDCard(String str) {
        String regExp = "(^\\d{15}$)|(^\\d{17}(\\d|X)$)";
        // 检查号码是否符合规范，包括长度，类型
        if (!Pattern.compile(regExp).matcher(str).matches()) {
            // 身份证号码为15位或者18位，15位时全为数字，18位前17位为数字，最后一位是校验位，可能为数字或字符X
            return false;
        }
        // 取身份证前两位,校验省份
        Map<String, String> city = new HashMap<String, String>();
        city.put("11", "北京");
        city.put("12", "天津");
        city.put("13", "河北");
        city.put("14", "山西");
        city.put("15", "内蒙古");
        city.put("21", "辽宁");
        city.put("22", "吉林");
        city.put("23", "黑龙江");
        city.put("31", "上海");
        city.put("32", "江苏");
        city.put("33", "浙江");
        city.put("34", "安徽");
        city.put("35", "福建");
        city.put("36", "江西");
        city.put("37", "山东");
        city.put("41", "河南");
        city.put("42", "湖北");
        city.put("43", "湖南");
        city.put("44", "广东");
        city.put("45", "广西");
        city.put("46", "海南");
        city.put("50", "重庆");
        city.put("51", "四川");
        city.put("52", "贵州");
        city.put("53", "云南");
        city.put("54", "西藏");
        city.put("61", "陕西");
        city.put("62", "甘肃");
        city.put("63", "青海");
        city.put("64", "宁夏");
        city.put("65", "新疆");
        city.put("71", "台湾");
        city.put("81", "香港");
        city.put("82", "澳门");
        city.put("91", "国外");
        // 取身份证前两位,校验省份
        String cityKey = str.substring(0, 2);
        if (!city.containsKey(cityKey)) {
            return false;
        }
        if (str.length() == 15) {
            // 身份证15位时，次序为省（3位）市（3位）年（2位）月（2位）日（2位）校验位（3位），皆为数字
            regExp = "^(\\d{6})(\\d{2})(\\d{2})(\\d{2})(\\d{3})$";
            if (Pattern.compile(regExp).matcher(str).matches()) {
                // 检查生日是否正确
                String birthday = "19" + str.substring(6, 12);
                if (!isBirthday(birthday)) {
                    return false;
                }
            } else {
                return false;
            }
        } else if (str.length() == 18) {
            // 身份证18位时，次序为省（3位）市（3位）年（4位）月（2位）日（2位）校验位（4位），校验位末尾可能为X
            regExp = "^(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9]|X)$";
            if (Pattern.compile(regExp).matcher(str).matches()) {
                // 检查生日是否正确
                String birthday = str.substring(6, 14);
                if (!isBirthday(birthday)) {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
        // 检验位的检测
        str = changeFivteenToEighteen(str); // 15位转18位
        if (str.length() != 18) {
            return false;
        }
        int[] arrInt = new int[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
        char[] arrCh = new char[] { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
        int cardTemp = 0;
        for (int i = 0; i < 17; i++) {
            cardTemp += Integer.parseInt(str.substring(i, i + 1)) * arrInt[i];
        }
        char valnum = arrCh[cardTemp % 11];
        if (valnum == str.substring(17, 18).charAt(0)) {
            return true;
        }
        return false;
    }

    /**
     * 检查生日是否合法
     *
     * @param str
     *            格式，如：19930101
     * @return true|合法
     */
    private static boolean isBirthday(String str) {
        if (str.length() != 8) {
            return false;
        }
        int y = Integer.parseInt(str.substring(0, 4));
        int m = Integer.parseInt(str.substring(4, 6));
        int d = Integer.parseInt(str.substring(6, 8));
        // 获取当前r
        Calendar c = Calendar.getInstance();
        int now_year = c.get(Calendar.YEAR);
        Date date = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            date = sdf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        c.setTime(date);
        if (c.get(Calendar.YEAR) != y || c.get(Calendar.MONTH) + 1 != m || c.get(Calendar.DAY_OF_MONTH) != d) {
            // 月或者日不是合法的范围
            return false;
        }
        // 年
        int per = now_year - y;
        if (per < 3 || per > 130) {
            return false;
        }
        return true;
    }

    /**
     * 15位身份证转18位身份证，传入18位不进行转换
     *
     * @param
     *
     * @return 18位身份证
     */
    private static String changeFivteenToEighteen(String str) {
        if (str.length() != 15) {
            return str;
        }
        int[] arrInt = new int[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
        char[] arrCh = new char[] { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
        int cardTemp = 0;
        str = str.substring(0, 6) + "19" + str.substring(6, str.length() - 6);
        for (int i = 0; i < 17; i++) {
            cardTemp += Integer.parseInt(str.substring(i, i + 1)) * arrInt[i];
        }
        return str + arrCh[cardTemp % 11];
    }






}
